package com.sqx.modules.pay.controller.app;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sqx.common.utils.Result;
import com.sqx.modules.app.dao.UserDao;
import com.sqx.modules.app.dao.UserMoneyDao;
import com.sqx.modules.app.dao.UserMoneyDetailsDao;
import com.sqx.modules.app.dao.UserVipDao;
import com.sqx.modules.app.entity.*;
import com.sqx.modules.common.dao.CommonInfoDao;
import com.sqx.modules.common.entity.CommonInfo;
import com.sqx.modules.course.dao.CourseUserDao;
import com.sqx.modules.course.entity.CourseUser;
import com.sqx.modules.orders.dao.OrdersDao;
import com.sqx.modules.orders.entity.Orders;
import com.sqx.modules.pay.bean.*;
import com.sqx.modules.pay.config.JYTH5Pay;
import com.sqx.modules.pay.dao.PayClassifyDao;
import com.sqx.modules.pay.dao.PayDetailsDao;
import com.sqx.modules.pay.dao.UserDramaDetailsDao;
import com.sqx.modules.pay.dao.UserDramaPointDao;
import com.sqx.modules.pay.entity.PayClassify;
import com.sqx.modules.pay.entity.PayDetails;
import com.sqx.modules.pay.entity.UserDramaDetails;
import com.sqx.modules.pay.entity.UserDramaPoint;
import com.sqx.modules.pay.util.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.sqx.modules.pay.config.JYTH5Pay.*;

@Slf4j
@RestController
@Api(value = "金运通", tags = {"金运通支付"})
@RequestMapping("/app/jytH5Pay")
public class JYTH5PayController {
    @Autowired
    private OrdersDao ordersDao;
    @Autowired
    private UserMoneyDao userMoneyDao;
    @Autowired
    private CommonInfoDao CommonInfoDao;
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserMoneyDetailsDao userMoneyDetailsDao;
    @Autowired
    private UserVipDao userVipDao;
    @Autowired
    private PayClassifyDao payClassifyDao;
    @Autowired
    private UserDramaPointDao userDramaPointDao;
    @Autowired
    private UserDramaDetailsDao userDramaDetailsDao;
    @Autowired
    private CourseUserDao courseUserDao;
    @Autowired
    private PayDetailsDao payDetailsDao;


    @ApiOperation("金运通H5支付接口")
    @PostMapping("/startJytH5Pay")
    public Result startJytH5Pay(HttpServletRequest req, HttpServletResponse resp, @ApiParam("订单编号") String orderId, @ApiParam("充值赠送剧点id") Integer payClassifyId) throws IOException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("application/json;charset=utf-8");  //这种方式有用

        SortedMap<String, String> map = BeanToMapUtil.getParameterMap(req);

        OP1001_BodyReq body = null;
        OP1001_HeaderReq head = null;

        try {
            body = (OP1001_BodyReq) BeanToMapUtil.convertMap(OP1001_BodyReq.class, map);
            body.setPayChannel("00");
            body.setPayMode("05");
            body.setTotalAmt("0.01");
            body.setSubject("这是一个测试订单");
//            body.setOrderId(orderId);
            body.setPayChannel("01");
            body.setOrderId("290071040001"+new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+RandomUtil.randomNumbers(6));
            body.setNotifyUrl("http://localhost:8182/app/jytH5Pay/notify");
            body.setSpbillCreatIp("127.0.0.1");
            head = (OP1001_HeaderReq) BeanToMapUtil.convertMap(OP1001_HeaderReq.class, map);
            head.setMerchantId("290071040001");
            System.out.println("=============="+body+"===================");
            System.out.println("---------------"+head+"===================");
        } catch (IllegalAccessException | InstantiationException | InvocationTargetException
                 | IntrospectionException e1) {
            e1.printStackTrace();
        }
        head = this.getOp1001Header(head, body.getOrderId());//设置head
        OP1001_TradeReq reqBean = new OP1001_TradeReq(head, body);
        String reqBeanStr = JSONArray.toJSONString(reqBean);

        String sign = RSAUtil.signMsg(reqBeanStr);
        System.out.println("报文明文：" + reqBeanStr);
        System.out.println("报文签名：" + sign);

        byte[] des_key = DESHelper.generateDesKey();
        Map<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("merchant_id", head.getMerchantId());
        paramMap.put("msg_enc", RSAUtil.encryptMsg(reqBeanStr, des_key));
        paramMap.put("key_enc", RSAUtil.encryptKey(des_key));
        paramMap.put("sign", sign);
        paramMap.put("mer_order_id", head.getTranFlowid());
        // 获取执行结果
        String res = HttpClient431Util.doPost(paramMap, ONEPAY_SERVER_URL);
        if (res == null) {
            System.err.println("服务器连接失败："+res);
            return Result.error("发生未知异常，请联系管理员");
        } else {
            System.out.println("连接服务器成功,返回结果" + res);
        }
        String[] respMsg = res.split(RESP_MSG_PARAM_SEPARATOR);

        String merchantId = respMsg[0].substring(RESP_MSG_PARAM_PREFIX_MERCHANT_ID.length());
        String respMsgEnc = respMsg[1].substring(JYTH5Pay.RESP_MSG_PARAM_PREFIX_MSG_ENC.length());
        String respKeyEnc = respMsg[2].substring(JYTH5Pay.RESP_MSG_PARAM_PREFIX_KEY_ENC.length());
        String respSign = respMsg[3].substring(JYTH5Pay.RESP_MSG_PARAM_PREFIX_SIGN.length());

        byte respKey[] = RSAUtil.decryptKey(respKeyEnc);

        String respMsgContext = RSAUtil.decrytXml(respMsgEnc, respKey);

        System.out.println("返回报文merchantId:" + merchantId);
        System.out.println("返回报文Json:" + respMsgContext);
        System.out.println("返回报文签名:" + respSign);

        if (!RSAUtil.verifyMsgSign(respMsgContext, respSign)) {
            System.err.println("返回报文校验失败");
            return Result.error("发生未知异常，请联系管理员");
        }
        JSON json = JSONObject.parseObject(respMsgContext);
        OP1001_TradeRsp tradeResp = (OP1001_TradeRsp) JSONObject.toJavaObject(json, OP1001_TradeRsp.class);
        String urlScheme = tradeResp.getBody().getUrlScheme();
        System.out.println("返回报文urlScheme:" + urlScheme);
//        resp.sendRedirect("h5pay-commit.jsp?urlScheme="+urlScheme);
        return Result.success().put("data",respMsgContext);
    }

    @ApiOperation("JYT H5支付回调")
    @PostMapping("/notify")
    @Transactional
    public Result jytH5PayNotify(HttpServletRequest request,HttpServletResponse response){
        //回调验签，获取订单编号，查询订单，修改订单状态

        String orderId = request.getParameter("orderId");
        LambdaQueryWrapper<Orders> ordersLambdaQueryWrapper = new LambdaQueryWrapper<>();
        ordersLambdaQueryWrapper.eq(Orders::getOrdersNo,orderId);
        Orders orders = ordersDao.selectOne(ordersLambdaQueryWrapper);

        //支付详情表记录
        PayDetails payDetails = new PayDetails();
        payDetails.setUserId(orders.getUserId());
        payDetails.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        payDetails.setOrderId(orders.getOrdersId().toString());

        if(ObjectUtils.isNotEmpty(orders)){
            UserEntity userEntity = userDao.selectById(orders.getUserId());
            if(orders.getOrdersType()==2&&userEntity.getInviterCode()!=null){//开会员
                payDetails.setType(2);
                LambdaQueryWrapper<UserEntity> userEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userEntityLambdaQueryWrapper.eq(UserEntity::getInvitationCode,userEntity.getInviterCode());
                UserEntity inviteUser = userDao.selectOne(userEntityLambdaQueryWrapper);
                //开会员给邀请人赏金
                LambdaQueryWrapper<UserMoney> userMoneyLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userMoneyLambdaQueryWrapper.eq(UserMoney::getUserId,inviteUser.getUserId());
                UserMoney userMoney = userMoneyDao.selectOne(userMoneyLambdaQueryWrapper);
                if(ObjectUtils.isEmpty(userMoney)){
                    userMoney = new UserMoney();
                    userMoney.setUserId(inviteUser.getUserId());
                    userMoney.setMoney(BigDecimal.ZERO);
                    userMoneyDao.insert(userMoney);
                }
                BigDecimal money = userMoney.getMoney();
                BigDecimal payMoney = orders.getPayMoney();
                CommonInfo one = CommonInfoDao.findOne(80);
                userMoney.setMoney(money.add(payMoney.multiply(new BigDecimal(one.getValue()))));
                userMoneyDao.updateById(userMoney);
                UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
                userMoneyDetails.setUserId(inviteUser.getUserId());
                userMoneyDetails.setMoney(payMoney.multiply(new BigDecimal(one.getValue())));
                userMoneyDetails.setClassify(3);
                userMoneyDetails.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                userMoneyDetails.setTitle("[邀请好友]好友名称："+userEntity.getUserName());
                userMoneyDetails.setContent("增加金额:"+payMoney.multiply(new BigDecimal(one.getValue()))+"元");
                userMoneyDetailsDao.insert(userMoneyDetails);
                //判断用户是否开过会员，生成会员记录
                LambdaQueryWrapper<UserVip> userVipLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userVipLambdaQueryWrapper.eq(UserVip::getUserId,orders.getUserId());
                UserVip userVip = userVipDao.selectOne(userVipLambdaQueryWrapper);
                if(ObjectUtils.isNotEmpty(userVip)){//用户开过会员
                    if (userVip.getIsVip()==2){//未过期给用户续期
                        //todo 保存过期时间
                        String endTime1 = userVip.getEndTime();
                        //string转为Date类型
                        Date expiredTime = null;
                        try {
                            expiredTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTime1);
                        } catch (ParseException e) {
                            e.printStackTrace();
                            throw new RuntimeException(e);
                        }
                        orders.setExpired(expiredTime);
                        ordersDao.updateById(orders);
                        String endTime = userVip.getEndTime();
                        //将string类型转为LocalDateTime类型
                        LocalDateTime localDateTime = LocalDateTime.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                        if (orders.getVipNameType()==0){//月卡
                            localDateTime = localDateTime.plusMonths(1);
                        } else if (orders.getVipNameType()==1) {//季卡
                            localDateTime = localDateTime.plusMonths(3);
                        } else if (orders.getVipNameType()==2) {//年卡
                            localDateTime = localDateTime.plusYears(1);
                        }
                        userVip.setCreateTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));
                        userVip.setEndTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(localDateTime));
                        userVipDao.updateById(userVip);
                    }else {//以前开过会员但过期了
                        LocalDateTime now = LocalDateTime.now();
                        userVip.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now));
                        if (orders.getVipNameType()==0){
                            LocalDateTime dateTime = now.plusMonths(1);//月卡
                            userVip.setEndTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(dateTime));
                        } else if (orders.getVipNameType()==1) {
                            LocalDateTime dateTime = now.plusMonths(3);
                            userVip.setEndTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(dateTime));
                        } else if (orders.getVipNameType()==2) {
                            LocalDateTime dateTime = now.plusYears(1);
                            userVip.setEndTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(dateTime));
                        }
                        userVipDao.insert(userVip);
                    }
                }else {//以前没开过会员
                    userVip = new UserVip();
                    userVip.setUserId(orders.getUserId());
                    userVip.setIsVip(2);
                    userVip.setVipNameType(orders.getVipNameType());
                    LocalDateTime now = LocalDateTime.now();
                    userVip.setCreateTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(now));
                    LocalDateTime localDateTime = null;
                    if (orders.getVipNameType()==0){//月卡
                        localDateTime = now.plusMonths(1);
                    } else if (orders.getVipNameType()==1) {//季卡
                        localDateTime = now.plusMonths(3);
                    } else if (orders.getVipNameType()==2) {//年卡
                        localDateTime = now.plusYears(1);
                    }
                    if(ObjectUtils.isNotEmpty(localDateTime)){
                        userVip.setEndTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(localDateTime));
                    }
                    userVipDao.insert(userVip);
                }
            }else if (orders.getOrdersType()==3){//充值到钱包
                if (ObjectUtils.isNotEmpty(orders.getPayClassifyId())){//购买剧点
                    PayClassify payClassify = payClassifyDao.selectById(orders.getPayClassifyId());
                    //给用户加剧点数
                    LambdaQueryWrapper<UserDramaPoint> userDramaPointLambdaQueryWrapper = new LambdaQueryWrapper<>();
                    userDramaPointLambdaQueryWrapper.eq(UserDramaPoint::getUserId,orders.getUserId());
                    UserDramaPoint userDramaPoint = userDramaPointDao.selectOne(userDramaPointLambdaQueryWrapper);
                    if (ObjectUtils.isEmpty(userDramaPoint)){
                        userDramaPoint = new UserDramaPoint();
                        userDramaPoint.setUserId(orders.getUserId().intValue());
                        userDramaPoint.setBalance(BigDecimal.ZERO);
                        userDramaPointDao.insert(userDramaPoint);
                    }
                    userDramaPoint.setBalance(userDramaPoint.getBalance().add(new BigDecimal(payClassify.getCoin())).add(new BigDecimal(payClassify.getGiveCoin())));
                    userDramaPointDao.updateById(userDramaPoint);
                    //生成用户加剧点数明细
                    UserDramaDetails userDramaDetails = new UserDramaDetails();
                    userDramaDetails.setUserId(orders.getUserId().intValue());
                    userDramaDetails.setAmount(new BigDecimal(payClassify.getCoin()).add(new BigDecimal(payClassify.getGiveCoin())));
                    userDramaDetails.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                    userDramaDetails.setType(1);//1增加 2减少
                    userDramaDetails.setTitle("剧点购买成功，订单号："+orders.getOrdersNo());
                    userDramaDetails.setContent("增加剧点："+new BigDecimal(payClassify.getCoin()).add(new BigDecimal(payClassify.getGiveCoin()))+"点");
                    userDramaDetailsDao.insert(userDramaDetails);
                }
                //给用户钱包加钱
                LambdaQueryWrapper<UserMoney> userMoneyLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userMoneyLambdaQueryWrapper.eq(UserMoney::getUserId, orders.getUserId());
                UserMoney userMoney = userMoneyDao.selectOne(userMoneyLambdaQueryWrapper);
                userMoney.setUserId(orders.getUserId());
                userMoney.setMoney(userMoney.getMoney().add(orders.getPayMoney()));
                userMoneyDao.updateById(userMoney);
                //生成用户钱包明细
                UserMoneyDetails userMoneyDetails = new UserMoneyDetails();
                userMoneyDetails.setUserId(orders.getUserId());
                userMoneyDetails.setContent("增加金额："+orders.getPayMoney()+"元");
                userMoneyDetails.setTitle("充值成功，订单号："+orders.getOrdersNo());
                userMoneyDetails.setMoney(orders.getPayMoney());
                userMoneyDetails.setType(1);
                userMoneyDetails.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                userMoneyDetailsDao.insert(userMoneyDetails);

            } else if (orders.getOrdersType()==1) {//剧点购买和零钱购买是单独的接口
                payDetails.setType(1);
                //我的短剧表记录
                CourseUser courseUser = new CourseUser();
                courseUser.setUserId(orders.getUserId());
                if(ObjectUtils.isNotEmpty(orders.getCourseDetailsId())){
                    courseUser.setClassify(2);
                    courseUser.setCourseId(orders.getCourseId());
                    courseUser.setCourseDetailsId(orders.getCourseDetailsId());
                }
                if(ObjectUtils.isEmpty(orders.getCourseDetailsId())){
                    courseUser.setClassify(1);
                    courseUser.setCourseId(orders.getCourseId());
                }
                courseUser.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                courseUser.setOrderId(orders.getOrdersId());
                courseUserDao.insert(courseUser);
            }

            payDetailsDao.insert(payDetails);
            //todo 支付方式
            orders.setPayWay(8);
            orders.setStatus(1);
            ordersDao.updateById(orders);
        }
        return Result.success();
    }

    @ApiOperation("JYT H5退款")
    @PostMapping("/jytH5Refund")
    public Result jytH5Refund(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("application/json;charset=utf-8");  //这种方式有用

        SortedMap<String, String> map = BeanToMapUtil.getParameterMap(req);
        OP1003_BodyReq body = null;
        OP1003_HeadReq head = null;

        try {
            body = (OP1003_BodyReq) BeanToMapUtil.convertMap(OP1003_BodyReq.class, map);
            body.setMerRefundFlowId("290071040001111111111111");
            body.setRefundAmt("0.01");
            body.setRefundChannel("02");
            body.setRefundReason("测试退款");
            body.setOriMerOrderId("290071040001111111111111");
            body.setMerNotifyUrl("http://localhost:8080/app/jytH5Pay/notify");
            head = (OP1003_HeadReq) BeanToMapUtil.convertMap(OP1003_HeadReq.class, map);
            head.setMerchantId("290071040001");
            head.setRespDesc("退款测试");
            head.setVersion("2.0.0");
            head.setTranCode("OP1001");
            head.setTranType("01");
            head.setRespCode("s00000000");
        } catch (IllegalAccessException | InstantiationException | InvocationTargetException
                 | IntrospectionException e1) {
            e1.printStackTrace();
        }
        head = this.getOp1003Header(head, body.getMerRefundFlowId());
        OP1003_TradeReq reqBean = new OP1003_TradeReq(head, body);
        String reqBeanStr = JSONArray.toJSONString(reqBean);

        String sign = RSAUtil.signMsg(reqBeanStr);
        System.out.println("报文明文：" + reqBeanStr);
        System.out.println("报文签名：" + sign);

        byte[] des_key = DESHelper.generateDesKey();
        Map<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("merchant_id", head.getMerchantId());
        paramMap.put("msg_enc", RSAUtil.encryptMsg(reqBeanStr, des_key));
        paramMap.put("key_enc", RSAUtil.encryptKey(des_key));
        paramMap.put("sign", sign);
        paramMap.put("mer_order_id", "123456789");

        // 获取执行结果
        String res = HttpClient431Util.doPost(paramMap, ONEPAY_SERVER_URL);

        System.out.println(res);
        if (res == null) {
            System.err.println("服务器连接失败");
            return Result.error("发生未知异常，请联系管理员");
        } else {
            System.out.println("连接服务器成功,返回结果" + res);
        }
        String[] respMsg = res.split(RESP_MSG_PARAM_SEPARATOR);

        String merchantId = respMsg[0].substring(RESP_MSG_PARAM_PREFIX_MERCHANT_ID.length());
        String respMsgEnc = respMsg[1].substring(JYTH5Pay.RESP_MSG_PARAM_PREFIX_MSG_ENC.length());
        String respKeyEnc = respMsg[2].substring(JYTH5Pay.RESP_MSG_PARAM_PREFIX_KEY_ENC.length());
        String respSign = respMsg[3].substring(JYTH5Pay.RESP_MSG_PARAM_PREFIX_SIGN.length());

        byte respKey[] = RSAUtil.decryptKey(respKeyEnc);

        String respMsgContext = RSAUtil.decrytXml(respMsgEnc, respKey);

        System.out.println("返回报文merchantId:" + merchantId);
        System.out.println("返回报文Json:" + respMsgContext);
        System.out.println("返回报文签名:" + respSign);

        resp.getWriter().write(JSONObject.toJSONString(res));
        System.out.println("连接服务器成功,返回结果" + res);
        return null;
    }


    private OP1001_HeaderReq getOp1001Header(OP1001_HeaderReq headerBean, String orderId) {
        headerBean.setVersion(JYTH5Pay.VERSION);
        headerBean.setTranType(JYTH5Pay.REQUEST_TRAN_TYPE);
        headerBean.setTranTime(
                DateTimeUtils.getDateTimeToString(new Date(), DateTimeUtils.DATETIME_FORMAT_YYYYMMDDHHMMSS));
        headerBean.setTranFlowid(orderId);
        headerBean.setTranCode(JYTH5Pay.TRAN_CODE);
        return headerBean;
    }

    private OP1003_HeadReq getOp1003Header(OP1003_HeadReq headerBean, String orderId) {
        headerBean.setVersion(JYTH5Pay.VERSION);
        headerBean.setTranType(JYTH5Pay.REQUEST_TRAN_TYPE);
        headerBean.setTranTime(
                DateTimeUtils.getDateTimeToString(new Date(), DateTimeUtils.DATETIME_FORMAT_YYYYMMDDHHMMSS));
        headerBean.setTranFlowid(orderId);
        headerBean.setTranCode(JYTH5Pay.TRAN_CODE);
        return headerBean;
    }
}
